LayoutBuilder in Flutter
LayoutBuilder is an important Flutter widget used to create responsive and adaptive user interfaces. It allows a widget to understand the layout constraints provided by its parent and build its UI accordingly.
Unlike MediaQuery, which provides information about the overall application window, LayoutBuilder provides the constraints available at the specific location where it is placed in the widget tree. Flutter's official documentation describes this as a useful approach when a custom widget needs to adapt to the space specifically given to that widget. Flutter Adaptive Layout Documentation
1. What is LayoutBuilder?
LayoutBuilder is a widget that provides a BoxConstraints object to its builder callback. These constraints describe the minimum and maximum width and height available to the widget.
Basic syntax:
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return YourWidget();
},
)
The constraints object allows you to access:
constraints.minWidth
constraints.maxWidth
constraints.minHeight
constraints.maxHeight
Flutter's layout model follows the basic rule: constraints go down, sizes go up, and the parent sets the position. Flutter Understanding Constraints
2. Why Use LayoutBuilder?
LayoutBuilder is useful when a widget needs to change its layout according to the amount of space actually provided by its parent.
For example, suppose a card is displayed inside a narrow container on one page and inside a wide container on another page. Using the overall screen size may not accurately represent the space available to the card.
LayoutBuilder solves this problem by providing the local constraints of the widget.
- Create responsive components.
- Change layouts according to available width.
- Build reusable responsive widgets.
- Choose different column counts.
- Switch between Row and Column layouts.
- Create responsive cards.
- Build adaptive dashboards.
- Create responsive navigation sections.
- Handle widgets placed inside different parent containers.
3. Basic LayoutBuilder Syntax
LayoutBuilder(
builder: (context, constraints) {
return Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
color: Colors.blue,
);
},
)
The builder receives two parameters:
| Parameter | Purpose |
|---|
context | Provides information about the widget's location in the widget tree. |
constraints | Provides the minimum and maximum size available from the parent. |
4. Understanding BoxConstraints
LayoutBuilder gives you a BoxConstraints object.
LayoutBuilder(
builder: (context, constraints) {
print(constraints.minWidth);
print(constraints.maxWidth);
print(constraints.minHeight);
print(constraints.maxHeight);
return const SizedBox();
},
)
A BoxConstraints contains four important values:
| Property | Meaning |
|---|
minWidth | Smallest width the widget can use. |
maxWidth | Largest width the widget can use. |
minHeight | Smallest height the widget can use. |
maxHeight | Largest height the widget can use. |
Flutter's official constraints documentation explains that a widget receives constraints from its parent and must choose a size within those constraints. Flutter Constraints Documentation
5. Simple LayoutBuilder Example
import 'package:flutter/material.dart';
class SimpleLayoutBuilder extends StatelessWidget {
const SimpleLayoutBuilder({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return Center(
child: Text(
"Available Width: ${constraints.maxWidth}",
style: const TextStyle(fontSize: 20),
),
);
},
),
);
}
}
6. Detecting Available Width
The most common use of LayoutBuilder is checking constraints.maxWidth.
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
return Text(
"Available width: $width",
);
},
)
This value represents the maximum width available to the LayoutBuilder from its parent.
7. Detecting Available Height
You can also access the maximum available height:
LayoutBuilder(
builder: (context, constraints) {
final height = constraints.maxHeight;
return Text(
"Available height: $height",
);
},
)
8. Creating Responsive Layouts
LayoutBuilder can be used to create different layouts according to available width.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const MobileLayout();
}
return const DesktopLayout();
},
)
The breakpoint should be selected according to the layout requirements. Flutter's adaptive-layout examples commonly use 600 logical pixels as an example breakpoint, but it is not a universal rule for every application. Flutter LayoutBuilder and Adaptive Layouts
9. Mobile and Tablet Layout Example
class ResponsiveContent extends StatelessWidget {
const ResponsiveContent({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Column(
children: [
Text("Mobile Layout"),
Text("Content displayed vertically"),
],
);
}
return const Row(
children: [
Expanded(
child: Text("Tablet/Desktop Item 1"),
),
Expanded(
child: Text("Tablet/Desktop Item 2"),
),
],
);
},
);
}
}
10. LayoutBuilder with Row
You can use LayoutBuilder to decide how many widgets should appear horizontally.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Row(
children: [
Expanded(child: Text("Item 1")),
Expanded(child: Text("Item 2")),
],
);
}
return const Row(
children: [
Expanded(child: Text("Item 1")),
Expanded(child: Text("Item 2")),
Expanded(child: Text("Item 3")),
Expanded(child: Text("Item 4")),
],
);
},
)
11. LayoutBuilder with Column
For narrow layouts, content can be displayed vertically.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 500) {
return const Column(
children: [
Text("Product Image"),
Text("Product Name"),
Text("Product Price"),
],
);
}
return const Row(
children: [
Expanded(child: Text("Product Image")),
Expanded(
child: Column(
children: [
Text("Product Name"),
Text("Product Price"),
],
),
),
],
);
},
)
12. LayoutBuilder for Responsive Cards
A reusable card can change its internal design based on its available width.
class ResponsiveCard extends StatelessWidget {
const ResponsiveCard({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 300) {
return Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
children: const [
Icon(Icons.person, size: 40),
SizedBox(height: 8),
Text("Small Card"),
],
),
),
);
}
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Row(
children: const [
Icon(Icons.person, size: 60),
SizedBox(width: 20),
Text("Wide Card"),
],
),
),
);
},
);
}
}
13. LayoutBuilder for Grid Columns
LayoutBuilder is very useful when the number of grid columns should depend on the available width.
LayoutBuilder(
builder: (context, constraints) {
int columns;
if (constraints.maxWidth < 500) {
columns = 2;
} else if (constraints.maxWidth < 800) {
columns = 3;
} else {
columns = 4;
}
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: 20,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text("Item ${index + 1}"),
),
);
},
);
},
)
14. LayoutBuilder with Dashboard Cards
class ResponsiveDashboard extends StatelessWidget {
const ResponsiveDashboard({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
int columns;
if (constraints.maxWidth < 600) {
columns = 1;
} else if (constraints.maxWidth < 1000) {
columns = 2;
} else {
columns = 4;
}
return GridView.count(
padding: const EdgeInsets.all(16),
crossAxisCount: columns,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: const [
DashboardCard(
title: "Users",
value: "1,250",
),
DashboardCard(
title: "Orders",
value: "540",
),
DashboardCard(
title: "Revenue",
value: "₹85,000",
),
DashboardCard(
title: "Pending",
value: "32",
),
],
);
},
);
}
}
class DashboardCard extends StatelessWidget {
final String title;
final String value;
const DashboardCard({
super.key,
required this.title,
required this.value,
});
@override
Widget build(BuildContext context) {
return Card(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title),
const SizedBox(height: 8),
Text(
value,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}
15. LayoutBuilder vs MediaQuery
One of the most important concepts is understanding when to use LayoutBuilder and when to use MediaQuery.
| LayoutBuilder | MediaQuery |
|---|
| Provides constraints from the parent widget. | Provides information about the application window. |
| Useful for local component layouts. | Useful for overall application-window decisions. |
Returns BoxConstraints. | Returns size and other media information. |
Uses constraints.maxWidth. | Uses MediaQuery.sizeOf(context).width. |
| Can adapt to the space given to a particular widget. | Can adapt to the overall window size. |
Flutter's official adaptive documentation specifically distinguishes these two approaches: use MediaQuery.sizeOf for the whole app window and LayoutBuilder when you need more local sizing information. Flutter Adaptive Apps Guide
16. Practical Difference Between MediaQuery and LayoutBuilder
Imagine an application window is 1200 pixels wide, but your widget is inside a container that is only 400 pixels wide.
MediaQuery.sizeOf(context).width might report approximately 1200 pixels, while LayoutBuilder can provide constraints that reflect the 400-pixel area available to that particular widget.
Container(
width: 400,
child: LayoutBuilder(
builder: (context, constraints) {
return Text(
"Local width: ${constraints.maxWidth}",
);
},
),
)
This local constraint-based behavior is one of the main reasons LayoutBuilder is useful for reusable responsive components.
17. LayoutBuilder Inside a Container
Container(
width: 500,
height: 300,
padding: const EdgeInsets.all(20),
child: LayoutBuilder(
builder: (context, constraints) {
return Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
color: Colors.blue,
child: const Center(
child: Text(
"Responsive Container",
style: TextStyle(color: Colors.white),
),
),
);
},
),
)
18. LayoutBuilder and Constraints
Suppose a parent provides these constraints:
minWidth = 0
maxWidth = 600
minHeight = 0
maxHeight = 400
LayoutBuilder can access them:
LayoutBuilder(
builder: (context, constraints) {
print(constraints.minWidth);
print(constraints.maxWidth);
print(constraints.minHeight);
print(constraints.maxHeight);
return const SizedBox();
},
)
The child must choose a size that satisfies the constraints passed by the parent. Flutter Box Constraints Guide
19. Tight Constraints
A tight constraint effectively forces a widget to use a specific size because its minimum and maximum values are equal.
For example:
BoxConstraints.tight(
const Size(300, 200),
)
This means:
minWidth = 300
maxWidth = 300
minHeight = 200
maxHeight = 200
20. Loose Constraints
Loose constraints allow a widget to choose a smaller size while still respecting a maximum size.
For example:
BoxConstraints(
minWidth: 0,
maxWidth: 500,
)
The widget can choose a width between 0 and 500 logical pixels, depending on the rest of the layout.
21. Unbounded Constraints
Sometimes a widget can receive an unbounded constraint in one direction. This means that the maximum size may be effectively infinite.
constraints.maxHeight == double.infinity
Unbounded constraints commonly appear in certain Row, Column, and scrollable layouts. They can cause errors when a child tries to expand infinitely.
For example, placing an Expanded widget inside a vertically scrolling ListView can produce constraint-related errors because the main-axis height may be unbounded.
Understanding constraints is therefore important when working with LayoutBuilder. Flutter Constraints Documentation
22. LayoutBuilder with ConstrainedBox
You can combine LayoutBuilder with ConstrainedBox to create controlled responsive layouts.
LayoutBuilder(
builder: (context, constraints) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: constraints.maxWidth > 700
? 700
: constraints.maxWidth,
),
child: const Text(
"Responsive content with maximum width",
),
);
},
)
23. LayoutBuilder with Center
A common pattern is to center content while limiting its width on larger layouts.
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth > 700
? 700.0
: constraints.maxWidth * 0.9;
return Center(
child: SizedBox(
width: width,
child: const Text(
"Centered Responsive Content",
),
),
);
},
)
24. LayoutBuilder for Responsive Forms
class ResponsiveForm extends StatelessWidget {
const ResponsiveForm({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Column(
children: [
TextField(
decoration: InputDecoration(
labelText: "First Name",
),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: "Last Name",
),
),
],
);
}
return const Row(
children: [
Expanded(
child: TextField(
decoration: InputDecoration(
labelText: "First Name",
),
),
),
SizedBox(width: 16),
Expanded(
child: TextField(
decoration: InputDecoration(
labelText: "Last Name",
),
),
),
],
);
},
);
}
}
25. LayoutBuilder for Login Pages
Login pages often need a narrow form on desktop and a full-width form on mobile.
class ResponsiveLogin extends StatelessWidget {
const ResponsiveLogin({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final formWidth = constraints.maxWidth > 500
? 420.0
: constraints.maxWidth * 0.9;
return Center(
child: SizedBox(
width: formWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
Text(
"Login",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 24),
TextField(
decoration: InputDecoration(
labelText: "Email",
),
),
SizedBox(height: 16),
TextField(
obscureText: true,
decoration: InputDecoration(
labelText: "Password",
),
),
],
),
),
);
},
);
}
}
26. LayoutBuilder for Product Cards
class ProductCard extends StatelessWidget {
const ProductCard({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final compact = constraints.maxWidth < 280;
if (compact) {
return Card(
child: Column(
children: const [
Icon(Icons.shopping_bag, size: 50),
Text("Product"),
Text("₹999"),
],
),
);
}
return Card(
child: Row(
children: const [
Padding(
padding: EdgeInsets.all(16),
child: Icon(
Icons.shopping_bag,
size: 70,
),
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Product",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text("₹999"),
],
),
],
),
);
},
);
}
}
27. LayoutBuilder for Sidebar and Details
A common adaptive pattern is to show a sidebar and details panel side-by-side when enough horizontal space is available.
class AdaptivePage extends StatelessWidget {
const AdaptivePage({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(
children: [
const SizedBox(
width: 280,
child: Sidebar(),
),
const VerticalDivider(width: 1),
const Expanded(
child: DetailsPanel(),
),
],
);
}
return const Sidebar();
},
);
}
}
Flutter's official adaptive-layout tutorial uses LayoutBuilder to switch between a compact navigation-based layout and a large layout containing a sidebar and details area. Flutter Adaptive Layout Tutorial
28. LayoutBuilder and Navigation
You can change navigation according to available width.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const NavigationBar(
destinations: [
NavigationDestination(
icon: Icon(Icons.home),
label: "Home",
),
NavigationDestination(
icon: Icon(Icons.settings),
label: "Settings",
),
],
);
}
return const NavigationRail(
selectedIndex: 0,
destinations: [
NavigationRailDestination(
icon: Icon(Icons.home),
label: Text("Home"),
),
NavigationRailDestination(
icon: Icon(Icons.settings),
label: Text("Settings"),
),
],
);
},
)
The exact breakpoint should depend on whether the available space is sufficient for the selected navigation design. Flutter's adaptive guidance gives 600 logical pixels as an example threshold for switching between compact and larger navigation patterns. Flutter Adaptive Design Guidance
29. LayoutBuilder and Wrap
Wrap can automatically move children to another line when there is insufficient horizontal space.
LayoutBuilder(
builder: (context, constraints) {
return Wrap(
spacing: 10,
runSpacing: 10,
children: const [
Chip(label: Text("Flutter")),
Chip(label: Text("Dart")),
Chip(label: Text("Firebase")),
Chip(label: Text("UI")),
Chip(label: Text("Responsive")),
],
);
},
)
This is useful for tags, filters, buttons, categories, and other content whose width can vary.
30. LayoutBuilder with ListView
LayoutBuilder can be placed inside scrollable layouts to adapt a section according to the constraints it receives.
ListView(
padding: const EdgeInsets.all(16),
children: [
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 500) {
return const Text("Compact content");
}
return const Text("Wide content");
},
),
],
)
When using LayoutBuilder inside complex scrollable structures, pay attention to which axis is bounded and which axis may be unbounded.
31. LayoutBuilder Inside a Row
When LayoutBuilder is used inside a Row, the constraints it receives depend on how the Row allocates space to that child.
Row(
children: [
const SizedBox(
width: 150,
child: Text("Sidebar"),
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return Text(
"Content width: ${constraints.maxWidth}",
);
},
),
),
],
)
Here, the Expanded widget gives the LayoutBuilder the remaining horizontal space.
32. LayoutBuilder Inside a Column
Column(
children: [
const SizedBox(
height: 100,
child: Text("Header"),
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return Center(
child: Text(
"Available height: ${constraints.maxHeight}",
),
);
},
),
),
],
)
The Expanded widget makes the LayoutBuilder receive the remaining available height.
33. LayoutBuilder and Expanded
Expanded and LayoutBuilder often work together when building responsive layouts.
Row(
children: [
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return Container(
height: 200,
color: Colors.blue,
child: Center(
child: Text(
"Width: ${constraints.maxWidth}",
style: const TextStyle(
color: Colors.white,
),
),
),
);
},
),
),
const SizedBox(width: 16),
Expanded(
child: Container(
height: 200,
color: Colors.green,
),
),
],
)
34. LayoutBuilder and Flexible
Flexible can also provide a bounded area in which LayoutBuilder can determine available space.
Row(
children: [
Flexible(
child: LayoutBuilder(
builder: (context, constraints) {
return Text(
"Available: ${constraints.maxWidth}",
);
},
),
),
const SizedBox(width: 20),
const Text("Other Content"),
],
)
35. Reusable Responsive Widget
A reusable responsive widget can hide breakpoint logic from the rest of the application.
class ResponsiveBuilder extends StatelessWidget {
final Widget mobile;
final Widget desktop;
const ResponsiveBuilder({
super.key,
required this.mobile,
required this.desktop,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return mobile;
}
return desktop;
},
);
}
}
Usage:
ResponsiveBuilder(
mobile: const MobileHomePage(),
desktop: const DesktopHomePage(),
)
36. ResponsiveBuilder with Three Layouts
class ResponsiveBuilder extends StatelessWidget {
final Widget small;
final Widget medium;
final Widget large;
const ResponsiveBuilder({
super.key,
required this.small,
required this.medium,
required this.large,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return small;
}
if (constraints.maxWidth < 1024) {
return medium;
}
return large;
},
);
}
}
37. Using LayoutBuilder with Builder Logic
Keep the builder callback focused on layout decisions.
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
final isCompact = width < 600;
final isMedium = width >= 600 && width < 1024;
if (isCompact) {
return const CompactLayout();
}
if (isMedium) {
return const MediumLayout();
}
return const LargeLayout();
},
)
38. LayoutBuilder and Adaptive Design
Responsive design generally means fitting the UI into the available space, while adaptive design also considers which layout is appropriate for that space.
LayoutBuilder is particularly useful for the measurement step because it provides the constraints at a specific point in the widget tree. Flutter's adaptive design guidance describes a three-step process: Abstract, Measure, and Branch. Flutter General Approach to Adaptive Apps
39. LayoutBuilder Build Timing
Unlike a normal Builder, LayoutBuilder's builder callback is invoked during layout and receives the constraints from the parent.
The callback can be called:
- The first time the widget is laid out.
- When the parent provides different constraints.
- When the LayoutBuilder configuration changes.
- When relevant dependencies used by the builder change.
Flutter's API documentation describes LayoutBuilder as a widget that defers building until layout so the builder can use the incoming constraints. LayoutBuilder API Documentation
40. LayoutBuilder vs Builder
| Builder | LayoutBuilder |
|---|
Provides BuildContext. | Provides BuildContext and BoxConstraints. |
| Used for creating a new build context. | Used for building according to layout constraints. |
| Does not provide parent size constraints. | Provides parent layout constraints. |
| Useful for accessing context-dependent information. | Useful for responsive and adaptive components. |
41. LayoutBuilder vs Container
Container is primarily a layout and decoration widget. It does not automatically provide the parent's constraints to a builder callback.
LayoutBuilder specifically exposes those constraints:
LayoutBuilder(
builder: (context, constraints) {
return Container(
width: constraints.maxWidth,
height: 100,
);
},
)
42. LayoutBuilder vs MediaQuery Example
class ComparisonExample extends StatelessWidget {
const ComparisonExample({super.key});
@override
Widget build(BuildContext context) {
final windowWidth =
MediaQuery.widthOf(context);
return Container(
width: 500,
padding: const EdgeInsets.all(20),
child: LayoutBuilder(
builder: (context, constraints) {
return Column(
children: [
Text(
"Window Width: $windowWidth",
),
Text(
"Local Width: ${constraints.maxWidth}",
),
],
);
},
),
);
}
}
This example demonstrates the difference between the overall application-window width and the local width available to a particular widget.
43. Common Mistakes with LayoutBuilder
Mistake 1: Confusing Screen Size with Local Constraints
LayoutBuilder does not directly provide the entire screen size. It provides the constraints passed by its parent.
Mistake 2: Ignoring Unbounded Constraints
Do not assume that maxWidth and maxHeight will always be finite.
Mistake 3: Using Too Many Breakpoints
Use breakpoints only when the layout actually needs to change. Avoid creating unnecessary breakpoint conditions.
Mistake 4: Hardcoding Everything
LayoutBuilder should be combined with flexible widgets instead of replacing every dimension with manually calculated values.
Mistake 5: Using Device Type Instead of Available Space
Responsive decisions should generally be based on the available constraints rather than assumptions about whether the hardware is a phone, tablet, or desktop.
Mistake 6: Putting Complex Business Logic in the Builder
Use the builder primarily for layout decisions. Keep data processing and business logic in appropriate application layers.
44. Best Practices
- Use LayoutBuilder when a widget needs to respond to its parent's available space.
- Use
constraints.maxWidth for width-based responsive decisions.
- Use
constraints.maxHeight when vertical space matters.
- Use MediaQuery when the overall application-window size is what matters.
- Use LayoutBuilder for reusable components that may be placed in different containers.
- Keep breakpoint logic simple and meaningful.
- Use
Expanded and Flexible to distribute available space.
- Use
Wrap when items should move naturally to additional lines.
- Use
ConstrainedBox or maximum widths when content should not grow indefinitely.
- Test components inside different parent sizes.
- Check for unbounded constraints when working with rows, columns, and scrollables.
- Do not assume a widget has the same width as the application window.
45. Complete Responsive LayoutBuilder Example
import 'package:flutter/material.dart';
class ResponsiveHome extends StatelessWidget {
const ResponsiveHome({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Responsive Layout"),
),
body: LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
if (width < 600) {
return const MobileLayout();
}
if (width < 1000) {
return const TabletLayout();
}
return const DesktopLayout();
},
),
);
}
}
class MobileLayout extends StatelessWidget {
const MobileLayout({super.key});
@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(16),
children: const [
Card(
child: ListTile(
leading: Icon(Icons.home),
title: Text("Home"),
),
),
Card(
child: ListTile(
leading: Icon(Icons.person),
title: Text("Profile"),
),
),
Card(
child: ListTile(
leading: Icon(Icons.settings),
title: Text("Settings"),
),
),
],
);
}
}
class TabletLayout extends StatelessWidget {
const TabletLayout({super.key});
@override
Widget build(BuildContext context) {
return GridView.count(
padding: const EdgeInsets.all(20),
crossAxisCount: 2,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
children: const [
Card(child: Center(child: Text("Home"))),
Card(child: Center(child: Text("Profile"))),
Card(child: Center(child: Text("Settings"))),
Card(child: Center(child: Text("Reports"))),
],
);
}
}
class DesktopLayout extends StatelessWidget {
const DesktopLayout({super.key});
@override
Widget build(BuildContext context) {
return Row(
children: [
const SizedBox(
width: 250,
child: ColoredBox(
color: Colors.blueGrey,
child: Center(
child: Text(
"Sidebar",
style: TextStyle(
color: Colors.white,
),
),
),
),
),
Expanded(
child: GridView.count(
padding: const EdgeInsets.all(30),
crossAxisCount: 4,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
children: const [
Card(child: Center(child: Text("Home"))),
Card(child: Center(child: Text("Profile"))),
Card(child: Center(child: Text("Settings"))),
Card(child: Center(child: Text("Reports"))),
],
),
),
],
);
}
}
46. Practical Use Cases
| Use Case | LayoutBuilder Usage |
|---|
| Responsive cards | Change card design based on available width. |
| Dashboards | Change the number of columns. |
| Forms | Switch between vertical and horizontal fields. |
| Navigation | Switch between compact and wide navigation. |
| Product grids | Change the number of products per row. |
| Sidebars | Show sidebar when sufficient horizontal space exists. |
| Reusable widgets | Adapt a component to different parent sizes. |
| Web layouts | Respond to browser resizing. |
47. Practice Exercises
- Create a widget that displays its
maxWidth and maxHeight.
- Create a responsive card that changes from Column to Row when its width reaches 400 pixels.
- Create a dashboard with 1 column below 600 pixels, 2 columns between 600 and 1000 pixels, and 4 columns above 1000 pixels.
- Create a responsive login form with a maximum width of 450 pixels.
- Create a product card that changes its design according to the available width.
- Create a sidebar that appears only when enough horizontal space is available.
- Create a reusable
ResponsiveBuilder widget.
- Use LayoutBuilder inside an
Expanded widget and display its available width.
- Build a responsive navigation interface using LayoutBuilder.
- Resize a Flutter web browser window and observe how the LayoutBuilder-based interface changes.
48. Quick Revision
| Concept | Explanation |
|---|
LayoutBuilder | Builds a widget according to constraints from its parent. |
BoxConstraints | Describes minimum and maximum width and height. |
maxWidth | Maximum horizontal space available. |
maxHeight | Maximum vertical space available. |
minWidth | Minimum horizontal space allowed. |
minHeight | Minimum vertical space allowed. |
MediaQuery | Useful for overall application-window information. |
LayoutBuilder + Expanded | Useful for responsive layouts inside flexible areas. |
LayoutBuilder + GridView | Useful for responsive grid columns. |
49. Official Flutter Resources
50. Flutter Course Resources
For structured Flutter learning and practical training, explore these resources:
Conclusion
LayoutBuilder is a powerful Flutter widget for creating responsive and adaptive components. It provides a BoxConstraints object containing the minimum and maximum width and height available from the parent. This makes LayoutBuilder especially useful when a widget needs to adapt to its own local space rather than the size of the entire application window.
Use MediaQuery when you need information about the overall application window and use LayoutBuilder when a component needs to respond to the constraints provided by its parent. Combining LayoutBuilder with widgets such as Expanded, Flexible, Wrap, GridView, ConstrainedBox, and SafeArea allows you to create flexible interfaces that work across different screen sizes and layouts. Learn more about Flutter adaptive layouts